package com.boesch.electroOffice.presentation.appointment;

import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import javax.faces.event.ActionEvent;
import javax.faces.event.ComponentSystemEvent;
import javax.faces.model.SelectItem;
import javax.portlet.PortletSession;

import org.apache.commons.lang.StringUtils;
import org.eclipse.datatools.connectivity.internal.UUID;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

import com.boesch.electroOffice.business.businessObject.AppointmentBusinessObject;
import com.boesch.electroOffice.business.businessObject.IdentifierBusinessObject;
import com.boesch.electroOffice.business.common.BusinessException;
import com.boesch.electroOffice.dataaccess.common.IllegalDataAccessException;
import com.boesch.electroOffice.model.electroOffice.Appointment;
import com.boesch.electroOffice.model.electroOffice.Identifier;
import com.boesch.electroOffice.model.enums.SessionParameter;
import com.boesch.electroOffice.model.enums.SubfunctionIdentifier;
import com.boesch.electroOffice.model.enums.UIMessages;
import com.boesch.electroOffice.model.messerli.Customer;
import com.boesch.electroOffice.model.wrapper.SelectBooleanItem;
import com.boesch.electroOffice.utils.MessageUtils;
import com.boesch.electroOffice.utils.PortletUtils;
import com.boesch.electroOffice.utils.SelectBooleanUtils;
import com.boesch.electroOffice.utils.UserUtils;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.log.Log;
import com.liferay.portal.kernel.log.LogFactoryUtil;
import com.liferay.portal.model.User;

/**
 * This class controls all the data is needed 
 * for the appointment form.
 * 
 * For more details about the package layering have a look at the documentation
 * of the project  or the project object model pom.xml
 * 
 * @author Ralph Koster
 *
 */
@Controller
@ManagedBean
@SessionScoped
public class AppointmentFormController implements Serializable {

	private static final long serialVersionUID = -8607165860005582500L;
	private static final Log log = LogFactoryUtil.getLog(AppointmentFormController.class);

	@Autowired
	private AppointmentBusinessObject appointmentBusinessObject;
	@Autowired
	private AppointmentNavigationController navigationController;
	@Autowired
	private IdentifierBusinessObject identifierBusinessObject;

	private Appointment appointment = new Appointment();
	private Customer customerAddress = new Customer();
	private Customer objectAddress = new Customer();
	private Customer invoiceAddress = new Customer();
	private Customer selectedAddress;

	private List<SelectBooleanItem> jobIdentifiers = new ArrayList<SelectBooleanItem>();
	private List<SelectItem> selectItemUsers = new ArrayList<SelectItem>();

	private Long selectedUserId = -1L;

	private boolean jobIdentifiersInitialized;
	private boolean isFirstAddressSet = true;

	public void loadData(ComponentSystemEvent event) {
		String appointmentId = PortletUtils.getSessionAttribute(SessionParameter.APPOINTMENT_ID.getValue());
		try {
			if ("true".equals(PortletUtils.getSessionAttribute(SessionParameter.RESET.getValue()))) {
				appointment = new Appointment();
			} else {
				if (StringUtils.isNumeric(appointmentId)) {
					appointment = appointmentBusinessObject.readAppointmentById(Integer.parseInt(appointmentId));
				}
			}

			if (null != appointment && null == appointment.getReportNumber()) {
				appointment.setReportNumber(generateUniqueReportNumber());
			}
			initializeSelectItemUsers();
			PortletUtils.setSessionAttribute(SessionParameter.RESET.getValue(), "false");
		} catch (IllegalDataAccessException e) {
			log.error("Failed to load appointment from database: " + appointmentId, e);
		} catch (BusinessException e) {
			log.error("Failed to load appointment from database: " + appointmentId, e);
		}
	}

	public void saveAppointment(ActionEvent actionEvent) {
		User currentUser = UserUtils.getCurrentUser();
		appointment.setLrUserId(selectedUserId);
		appointment.setIdCustomerAddress(customerAddress.getCustomerId());
		appointment.setIdInvoiceAddress(customerAddress.getCustomerId());
		appointment.setIdObjectAddress(objectAddress.getCustomerId());
		List<Identifier> jobIdentifiers = retrieveSelectedJobIdentifiers();
		appointment.setJobIdentifiers(jobIdentifiers);
		try {
			if (appointment.getId() < 1) {
				appointmentBusinessObject.saveAppointment(appointment, currentUser);
				MessageUtils.addInfoMessage(UIMessages.SAVE_APPOINTMENT_OK.getMessage());
			} else {
				appointmentBusinessObject.updateAppointment(appointment, currentUser);
				MessageUtils.addInfoMessage(UIMessages.UPDATE_APPOINTMENT_OK.getMessage());
			}
		} catch (BusinessException e) {
			log.error("Error while saving appointment.", e);
			MessageUtils.addErrorMessage(UIMessages.SAVE_APPOINTMENT_ERROR.getMessage() + " " + UIMessages.SAVE_APPOINTMENT_ERROR.getNextSteps());
		} catch (IllegalDataAccessException e) {
			log.error("Error while saving appointment.", e);
			MessageUtils.addErrorMessage(UIMessages.SAVE_APPOINTMENT_ERROR.getMessage() + " " + UIMessages.SAVE_APPOINTMENT_ERROR.getNextSteps());
		}
	}

	public void cancel(ActionEvent actionEvent) {
		PortletSession session = PortletUtils.getPortletSession();
		session.setAttribute(SessionParameter.SUBFUNCTION_KEY.getValue(), SubfunctionIdentifier.MY_APPOINTMENTS.getValue());
		navigationController.setNavigationPath("jsf/appointment/appointment_list.xhtml");
	}

	public Appointment getAppointment() {
		return appointment;
	}

	public Customer getCustomerAddress() {
		return customerAddress;
	}

	public Customer getObjectAddress() {
		return objectAddress;
	}

	public Customer getInvoiceAddress() {
		return invoiceAddress;
	}

	public void setAddresses(ActionEvent event) {
		PortletSession session = PortletUtils.getPortletSession();
		String objectKind = (String) session.getAttribute("addressKind");
		if (null != selectedAddress) {
			if (isFirstAddressSet) {
				customerAddress = selectedAddress;
				objectAddress = selectedAddress;
				invoiceAddress = selectedAddress;
			} else if ("customer".equals(objectKind)) {
				customerAddress = selectedAddress;
			} else if ("object".equals(objectKind)) {
				objectAddress = selectedAddress;
			} else if ("invoice".equals(objectKind)) {
				invoiceAddress = selectedAddress;
			}
		}
	}

	public Customer getSelectedAddress() {
		return selectedAddress;
	}

	public void setSelectedAddress(Customer selectedAddress) {
		this.selectedAddress = selectedAddress;
	}

	public List<SelectBooleanItem> getJobIdentifiers() {
		if (!jobIdentifiersInitialized) {
			initJobIdentifiers();
		}
		return jobIdentifiers;
	}

	public List<SelectItem> getUserList() {
		return selectItemUsers;
	}

	public long getSelectedUserId() {
		return selectedUserId;
	}

	public void setSelectedUserId(long selectedUserId) {
		this.selectedUserId = selectedUserId;
	}

	public boolean isOneAddressSelected() {
		return null != selectedAddress;
	}

	private List<Identifier> retrieveSelectedJobIdentifiers() {
		List<Identifier> list = new ArrayList<Identifier>();
		if (null != jobIdentifiers) {
			for (SelectBooleanItem item : jobIdentifiers) {
				if (item.isSelected()) {
					list.add((Identifier) item.getItem());
				}
			}
		}
		return list;
	}

	private void initJobIdentifiers() {
		try {
			List<Identifier> jobIdentif = identifierBusinessObject.readIdentifiersByEntity("JOB-IDENTIFIER");
			jobIdentifiers = SelectBooleanUtils.convertObjectsToSelectBooleanItems(jobIdentif);
			List<Identifier> jobIdentifiers = appointment.getJobIdentifiers();
			if (null != jobIdentifiers) {
				handleSelectedJobIdentifiers(jobIdentifiers);
			}
			jobIdentifiersInitialized = true;
		} catch (BusinessException e) {
			log.error("Failed to read jobIdentifiers from dataaccess");
		} catch (IllegalDataAccessException e) {
			log.error("Failed to read jobIdentifiers from dataaccess");
		}
	}

	private void handleSelectedJobIdentifiers(List<Identifier> jobIdentif) {
		for (Identifier identifier : jobIdentif) {
			for (SelectBooleanItem selectBoolean : jobIdentifiers) {
				Identifier item = (Identifier) selectBoolean.getItem();
				if (item.getId() == identifier.getId()) {
					selectBoolean.setSelected(true);
				}
			}
		}
	}

	private void initializeSelectItemUsers() {
		try {
			selectItemUsers = new ArrayList<SelectItem>();
			List<User> users = UserUtils.getAllUsers();
			for (User user : users) {
				String userId = String.valueOf(user.getUserId());
				String fullName = user.getFullName();
				String comment = user.getComments();
				SelectItem item = new SelectItem(userId, fullName, comment);
				selectItemUsers.add(item);
			}
		} catch (SystemException e) {
			log.error("Failed to load users from liferay database.", e);
		}
	}

	private String generateUniqueReportNumber() {
		UUID uniqueKey = UUID.createUUID();
		return uniqueKey.toString();
	}
}
